#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"
#include "Dict.hpp"
#include "InetAddr.hpp"

using namespace LogModule;

const int defaultfd = -1;

using func_t = std::function<std::string(const std::string&)>;

class UdpServer{
public:
	UdpServer(uint16_t port, func_t func) : _port(port), _isrunning(false), _func(func){
		_sockfd = defaultfd;
	}

	void Init(){
		// 创建套接字类型
		_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
		if(_sockfd < 0){
			LOG(LogLevel::FATAL)<<"create socket fail";
			exit(1);
		}

		LOG(LogLevel::INFO)<<"create socket success";
		struct sockaddr_in local;
		local.sin_family = AF_INET;
		local.sin_port = htons(_port);

		local.sin_addr.s_addr = INADDR_ANY; // 将地址转换为网络字节序
		int n = bind(_sockfd, (struct sockaddr*)&local, sizeof(local));
		if(n < 0){
			LOG(LogLevel::FATAL)<<"bind socket fail";
			exit(1);
		}

		LOG(LogLevel::INFO)<<"bind socket success";
	}

	void Start(){
		_isrunning = true;
		Dict dict;
		if(!dict.LoadDict()){
			LOG(LogLevel::FATAL)<<"load dict fail";
			return;
		}
		while(_isrunning){
			char buffer[1024]; // 用于存储接收的数据
			struct sockaddr_in peer; // 用于输出客户端地址
			socklen_t len = sizeof(peer);
			int n = recvfrom(_sockfd, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
			if(n > 0){
				buffer[n] = 0;
				InetAddr peer_addr(peer);
				LOG(LogLevel::DEBUG)<<"["<<peer_addr.Ip()<<":"<<peer_addr.Port()<<"]: "<<buffer;
				
				std::string result = dict.Translate(buffer, peer_addr);
				sendto(_sockfd, result.c_str(), result.size(), 0, (struct sockaddr*)&peer, len);
			}

			
		}
	}

	~UdpServer(){
		if(_sockfd != defaultfd){
			close(_sockfd);
		}
	}

private:
	int _sockfd; // 套接字文件描述符
	uint16_t _port; // 端口号
	bool _isrunning;
	func_t _func; // 回调函数
};